#pragma once

#include <vector>
#include <queue>
#include <unistd.h>
#include "Thread.hpp"
#include "Task.hpp"
#include "LockGuard.hpp"
#include "Log.hpp"

using std::queue;
using std::vector;

static const int N = 5; // 线程数[默认]

// 最终版本V4：将线程池修改为单例模式（懒汉），新增 GC 垃圾回收方式，确保单例对象被销毁（detache 次线程后，方便观察）

template <class T>
class ThreadPool
{
private:
    // 无法通过常规手段创建对象
    ThreadPool(int num = N)
        : _threads(num), _num(num)
    {
        // 锁 及 条件变量 的初始化
        //  pthread_mutex_init(&_mtx, nullptr);  //不用初始化 锁 了
        pthread_cond_init(&_cond, nullptr);

        static_cast<void>(ThreadPool<T>::_gc);
    }

    // 删除拷贝构造、赋值重载
    ThreadPool(const ThreadPool<T> &tp) = delete;
    ThreadPool<T> &operator=(const ThreadPool<T> &tp) = delete;

public:
    ~ThreadPool()
    {
        // 持久化等工作

        for (auto &t : _threads)
            t.join();

        // 销毁
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_cond);
    }

    // 获取单例对象
    static ThreadPool<T> *GetInstace()
    {
        // 双检查加锁
        if (_pool == nullptr)
        {
            // 加锁保护
            LockGuard lg(&_mtx_new);
            if (_pool == nullptr)
            {
                // 第一次获取，创建对象
                _pool = new ThreadPool<T>();
                _pool->init();
                _pool->start();
            }
        }

        return _pool;
    }

    // 销毁单例对象
    static void DelInstace()
    {
        logMessage(Debug, "DelInstace()");

        LockGuard lg(&_mtx_new);
        delete _pool;
        _pool = nullptr;
    }

    // 垃圾回收类
    class GC
    {
    public:
        GC()
        {
            logMessage(Debug, "GC()");
        }

        ~GC()
        {
            logMessage(Debug, "~GC()");
            DelInstace();
        }
    };

    static GC _gc;

    // 初始化
    void init()
    {
        for (int i = 0; i < _num; i++)
            _threads[i] = Thread(i, threadRoutine, this);
    }

    static void threadRoutine(void *arg)
    {
        // 获取 this 指针
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(arg);

        // pthread_detach(pthread_self());

        while (true)
        {
            // 1、检测有没有任务，执行 或 等待
            T t;

            {
                LockGuard lg(tp->getMutex());
                while (tp->isEmpty())
                {
                    // 没有任务，等待
                    tp->threadWait();
                }
                t = tp->popTask();
            }

            t(); // 执行任务
            logMessage(Debug, "threadRoutine done");
        }
    }

    // 启动
    void start()
    {
        for (auto &t : _threads)
            t.run();
    }

    // 装载任务
    void pushTask(const T &t)
    {
        LockGuard lg(getMutex());
        _tasks.push(t);
        threadWeakUp(); // 装载任务后，唤醒线程，执行任务
    }

    // 获取任务
    T popTask()
    {
        T t = _tasks.front();
        _tasks.pop();
        return t;
    }

    // 检查
    void check()
    {
        for (auto &t : _threads)
            std::cout << t.getName() << " " << t.getID() << " " << t.getStatus() << std::endl;
        ;
    }

protected:
    // 封装各种功能
    void threadWait()
    {
        pthread_cond_wait(&_cond, &_mtx);
    }

    void threadWeakUp()
    {
        pthread_cond_signal(&_cond);
    }

    bool isEmpty()
    {
        return _tasks.empty();
    }

    pthread_mutex_t *getMutex()
    {
        return &_mtx;
    }

private:
    vector<Thread> _threads; // 存放线程
    int _num;                // 线程数

    queue<T> _tasks;             // 存放任务（自动扩容）
    static pthread_mutex_t _mtx; // 保护任务队列，并发访问时互斥
    pthread_cond_t _cond;        // 条件变量，当没有任务时，线程睡眠

    // 创建唯一的静态线程池对象
    static ThreadPool<T> *_pool;
    static pthread_mutex_t _mtx_new; // 保护单例对象的创建，互斥
};

// 类外初始化
template <class T>
ThreadPool<T> *ThreadPool<T>::_pool = nullptr; // 懒汉 初始化为空

// 锁为静态锁
template <class T>
pthread_mutex_t ThreadPool<T>::_mtx = PTHREAD_MUTEX_INITIALIZER; // 初始化

template <class T>
pthread_mutex_t ThreadPool<T>::_mtx_new = PTHREAD_MUTEX_INITIALIZER; // 初始化

template <class T>
typename ThreadPool<T>::GC ThreadPool<T>::_gc;